/** 
 **  Program:               JAC444A/Assignment2
 **  Author:                Honghui Chen
 **  Date:                  2013-06-15
 **  Propose:               How to apply for HashMap, Exception and reading files, 
 **                         calculate rows and column using rules file
 **/

package a2;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;

public class Calc {
	
	/** Create method "inFile(String file)", read every row from file.
	 ** Put them into HashMap. Every separated string read as value.
	 ** And sign an integer key for each one. 
	 ** For example, first row and first column is 101;
	 ** the 15th row and 24th column is 1524
	 ** So for this program, Maximum columns are 99 and rows are not limited.
	 ** This function return a HashMap
	 **/
	
	public HashMap<Integer, String> inFile(String file)throws IOException{
					
			BufferedReader br = new BufferedReader(new FileReader(file));
			String content = null;		
			int lineNumber = 1;
			HashMap<Integer, String> map = new HashMap<Integer, String>();

		
		while((content = br.readLine()) != null){	// read line by line from file		
			String[] ary = content.trim().split("\\s+");	
			for(int i = 0; i < ary.length; i++){
			    int k=lineNumber*100 + i+1;     // key format is (x)xxyy
			    map.put(k, ary[i]);			
			}								
			lineNumber++;}
		    br.close();
		 return map;   
		}

	public static void main(String[] args) throws IOException, A2Exception {
		
		    HashMap<Integer, String> map;
		    HashMap<Integer, String> map1;
		    Calc ca = new Calc();
		    
		    map=ca.inFile(args[0]); //map is read from spread file
		    map1=ca.inFile(args[1]); //map1 is read from rules file
		   
			int[] s=new int[map.size()];
		    for (int j = 0; j < map.size(); j++) {
				Integer key = (Integer) map.keySet().toArray()[j];			 
				s[j]=key;
        		 } // all keys of map (spread file) put into array s 
		    Arrays.sort(s);
		    
		    int tr=1, tc=1;             // total rows and total columns spread sheet
		    for (int j = 0; j < map.size(); j++) {				    	 
		    	 if(s[j]/100>=tr) { tr=s[j]/100; }
		    	 if(s[j]%100>=tc) { tc=s[j]%100; }
		    }	 		    
		   
		    int[] s1=new int[map1.size()];
		    for (int j = 0; j < map1.size(); j++) {
				Integer key = (Integer) map1.keySet().toArray()[j];			 
				s1[j]=key;
        		 } // all keys of map1 (rules file) put into array s1 
		    Arrays.sort(s1);
		    	    
		    int[] ik = new int[4]; // ik is 4 value each row of rules file
		    
		    for (int jj = 0; jj < map1.size(); jj++) {				    	 
		    	
		      if(s1[jj]%100 == 2){  //retrieve function word from second column
		    	
		    	  // convert xx:xx format to xx0xx format
		    	  for(int i=0; i<4; i++){
		    		if(i==1) continue;
		    		String[] sa =new String[2];
		    		sa = (map1.get(s1[jj-1+i])).split(":"); 		    		
		    		if(Integer.valueOf(sa[1])<10){
		    		ik[i]=Integer.valueOf((map1.get(s1[jj-1+i])).replace(":", "0"));
		    		}
		    		else {
		    		ik[i]=Integer.valueOf((map1.get(s1[jj-1+i])).replace(":", ""));
		    		}
		    		 }		    		 
		    	
		    	  // throw disobeyed rule to catch exception
				    try{
				    	if(ik[2]/100>ik[3]/100){
				            throw new A2Exception.RowException();
				            }
				       }catch(A2Exception.RowException e){
				    	   e.print();
				    	   if((ik[3]/100<=tr)&&(ik[2]/100<=tr)) {
				    	   continue;
				    	   }
				       } 
				    try{
				        if(ik[2]%100 > ik[3]%100){
				            throw new A2Exception.ColumnException();	
				            }
				       }catch(A2Exception.ColumnException e){
				    	   e.print();
				    	   if((ik[3]%100<=tc)&&(ik[2]%100<=tc)) {
				    	   continue;
				    	   }
				       }
				    try{
				        if(((ik[3]/100-ik[2]/100)==(ik[3]%100-ik[2]%100))&&(ik[3]!=ik[2])) {
				            throw new A2Exception.DiagonalException();	
				            }
				       }catch(A2Exception.DiagonalException e){
				    	   e.print();
				    	   continue;
				       }	
				    try{
				        if((ik[3]/100>tr)||(ik[2]/100>tr)) {
				            throw new A2Exception.RowOutOfRangeException();	
				            }
				       }catch(A2Exception.RowOutOfRangeException e){
				    	   e.print();
				    	    continue;
				       }	
				    try{
				        if((ik[3]%100>tc)||(ik[2]%100>tc)) {
				            throw new A2Exception.ColumnOutOfRangeException();	
				            }
				       }catch(A2Exception.ColumnOutOfRangeException e){
				    	   e.print();
				    	    continue;
				       }
		   int count = 1;
	       if(ik[3]%100==ik[2]%100){			    
		      count=(ik[3]-ik[2])/100 + 1;
	          } else if(ik[3]/100==ik[2]/100){ 
	          count=(ik[3]-ik[2])%100 + 1;  
	          }else { continue; }
		// count is how many rows or columns need to sum.		
		int[] iv = new int[count];
		          int first=ik[2];
		          
                  for(int d=0; d<count; d++){                     	  
		          iv[d]=Integer.valueOf(map.get(first));
		           if(ik[3]%100==ik[2]%100){
		           first=first+100;
		           } 
		           else {
			           first=first+1;
			           } 
                  }
                  Arrays.sort(iv);
                  int sum=0; // calculate sum from starting row (column) final row (column)
                  for(int i=0;i<count;i++) { 
		             sum=sum+iv[i];	
		           }	  
 		 
		         switch(map1.get(s1[jj])){
		   case "mean":  
			   double temp = (double)sum/count + 0.5;
		  	map.put(ik[0],((int)temp+""));		    	     
		  	break;
		   case "min":
		  	map.put(ik[0],(iv[0]+""));		    	
		      break;
		   case "max":
		  	map.put(ik[0],(iv[count-1]+""));
		      break;
		   case "sum":
		  	map.put(ik[0],(sum+""));	    	
		      break;
		         }     //switch
           		           
		         }         //if second column is function word
		    }         //   for
			    		    
		    int x=1;
		    for (int j = 0; j < map.size(); j++) {				    	 
		    	 if((s[j]-(x*100))>=100){
		    		 x++;
		    		 System.out.println(""); 
		    	 }
		    	 System.out.print(map.get(s[j])+"\t");
		    }		    
			System.out.println(""); 					
	}
}


